#!/bin/bash
# Script: gen-pkg-spec.sh
# Version: 1.0
# Author: Your Name
# Description: Generate spec files for ROS packages

# 首先加载 base.sh
# Use absolute path or relative path from script location for robustness
script_dir=$(dirname "$(readlink -f "$0")")
base_sh_path="${script_dir}/base.sh"

if [ ! -f "${base_sh_path}" ]; then
    # Use echo here as logging functions are not yet available
    echo "Error: base.sh not found at ${base_sh_path}"
    exit 1
fi

# 加载基础配置和日志函数
# Source base.sh only once
info_log "Loading base.sh from ${base_sh_path}..." # This will fail if base.sh hasn't defined info_log yet. Consider sourcing first.
# Let's source first, then log.
. "${base_sh_path}"
info_log "base.sh loaded successfully."

# 检查必要的环境变量 (使用日志函数)
info_log "Checking environment variables..."
if [ -z "$ROS_DISTRO" ]; then
    error_log "ROS_DISTRO not set"
    exit 1
fi
info_log "ROS_DISTRO: '$ROS_DISTRO'"

if [ -z "$AGIROS_DISTRO" ]; then
    error_log "AGIROS_DISTRO not set"
    exit 1
fi
info_log "AGIROS_DISTRO: '$AGIROS_DISTRO'"

if [ -z "$SRC_TAR_FROM" ]; then
    error_log "SRC_TAR_FROM not set"
    exit 1
fi
info_log "SRC_TAR_FROM: '$SRC_TAR_FROM'"

# Log other important variables loaded from base.sh
info_log "OUTPUT: $OUTPUT"
info_log "ROOT: $ROOT"
info_log "ROS_SRC_BASE: $ROS_SRC_BASE"
info_log "ROS_REPO_BASE: $ROS_REPO_BASE"
info_log "ROS_DEPS_BASE: $ROS_DEPS_BASE"


# 检查必要的目录 (使用日志函数)
info_log "Checking directories..."
if [ ! -d "$ROS_SRC_BASE" ]; then
    error_log "ROS_SRC_BASE directory not found: $ROS_SRC_BASE"
    exit 1
fi
info_log "ROS_SRC_BASE directory exists: $ROS_SRC_BASE"

if [ ! -d "$ROOT/template" ]; then
    error_log "template directory not found: $ROOT/template"
    exit 1
fi
info_log "template directory exists: $ROOT/template"

# 检查必要的命令是否存在 (使用日志函数)
info_log "Checking required commands..."
for cmd in grep awk sed tar cp mkdir find wc cut sort uniq mktemp; do # Added mktemp if you plan to use it
    if ! command -v $cmd &> /dev/null; then
        error_log "Required command '$cmd' not found"
        exit 1
    fi
    # Use debug_log for successful checks to reduce noise
    debug_log "Command '$cmd' found: $(which $cmd)"
done
info_log "All required commands found."

# Default values
specific_pkg=""

usage()
{
    echo "Usage: $0 [options]"
    echo "Options:"
    echo "  -p, --package <package_name>    Generate spec for specific package only"
    echo "  -h, --help                      Show this help message"
    exit 1
}

# Parse command line arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -p|--package)
            specific_pkg="$2"
            shift 2
            ;;
        -h|--help)
            usage
            ;;
        *)
            echo "Unknown option: $1"
            usage
            ;;
    esac
done

# 初始化必要的文件路径
ROS_PKG_SRC=${OUTPUT}/ros-pkg-src.list
ROS_PKG_LIST=${OUTPUT}/ros-pkg.list
ROS_PACKAGE_FIX=${ROOT}/package_fix
ROS_PKG_REMAP=${ROOT}/spec_fix/pkg.remap

# 检查必要的文件 (使用日志函数)
check_required_files() {
    info_log "Checking required files..."
    if [ ! -f "$ROS_PKG_SRC" ]; then
        error_log "Required file $ROS_PKG_SRC not found. Please run get-pkg-deps.sh first."
        exit 1
    fi
    info_log "Found required file: $ROS_PKG_SRC"

    if [ ! -f "$ROS_PKG_LIST" ]; then
        error_log "Required file $ROS_PKG_LIST not found. Please run get-pkg-deps.sh first."
        exit 1
    fi
    info_log "Found required file: $ROS_PKG_LIST"
    info_log "Required files check passed."
}

# 验证参数 (使用日志函数)
if [ -n "$specific_pkg" ]; then
    info_log "Specific package requested: $specific_pkg"
    # 首先检查必要的文件
    check_required_files

    # Use grep -q for quieter check
    if ! grep -qP "^${specific_pkg}[[:blank:]]" "$ROS_PKG_SRC"; then
        error_log "Package '$specific_pkg' not found in $ROS_PKG_SRC"
        exit 1
    fi
    info_log "Package '$specific_pkg' found in $ROS_PKG_SRC."
fi

prepare()
{
    info_log "Starting prepare phase..."
    
    if [ -z "${ROS_SRC_BASE}" ]; then
        echo "Error: ROS_SRC_BASE not set"
        exit 1
    fi

    if [ ! -d "${ROS_SRC_BASE}" ]; then
        echo "Error: ROS_SRC_BASE directory not found: $ROS_SRC_BASE"
        exit 1
    fi

    check_required_files

    if [ -z "$specific_pkg" ]; then
        # 增加检查，如果目录非空且包含内容，可能需要警告或更复杂的逻辑
        if [ -d "${ROS_REPO_BASE}" ] && [ "$(ls -A "${ROS_REPO_BASE}")" ]; then
             warn_log "ROS_REPO_BASE (${ROS_REPO_BASE}) exists and is not empty. Removing it."
             # 或者考虑添加一个全局锁来保护这个操作
        fi
        info_log "Removing existing ROS_REPO_BASE directory: ${ROS_REPO_BASE}"
        if ! rm -rf "${ROS_REPO_BASE}"; then
            error_log "Failed to remove directory: ${ROS_REPO_BASE}"
            exit 1
        fi
    fi
    info_log "Creating ROS_REPO_BASE directory: ${ROS_REPO_BASE}"
    if ! mkdir -p "${ROS_REPO_BASE}"; then
         error_log "Failed to create directory: ${ROS_REPO_BASE}"
         exit 1
    fi

    info_log "Prepare phase completed"
}

spec_fix()
{
	pkg=$1
	deps_suffix=$2
	require_type=$3
	key_word=$4
	require_file=$5

	spec_fix_file=${ROOT}/spec_fix/$pkg.${deps_suffix}

	[ ! -f ${spec_fix_file} ] && return

	if [ -f ${require_file} ]
	then
		for dep in `grep "^\-" ${spec_fix_file} | sed -e "s#^\-##g"`
		do
			sed -i "/^$require_type: *$dep\$/d" $require_file
		done
	fi

	grep -q "^\+" $spec_fix_file
	[ $? -ne 0 ] && return 
	
	grep "^\+" $spec_fix_file | sed -e "s#^\+#$require_type: #g" >> ${require_file}
}

rename_requires()
{
	require_file=$1

	while read deb_pkg rpm_pkg
	do
		sed -i "s#Requires: ${deb_pkg}\$#Requires: ${rpm_pkg}#g" $require_file
	done <${ROS_PKG_REMAP}
}

replace_key_word()
{
	key_word=$1
	input_file=$2
	replace_file=$3

	if [ ! -f ${input_file} ]
	then
                sed -i "/${key_word}/d" $replace_file
		return
	fi

        desc_wc=`cat ${input_file} | wc -l`
        if [ "$desc_wc" = "1" ]
        then
                desc=`cat ${input_file}`
                sed -i "s#${key_word}#$desc#g" $replace_file
        else
                desc=`cat ${input_file} | sed ":a;N;s/\n/ROS_DESC_CRLF/g;ta"`
                sed -i "s^${key_word}^$desc^g" $replace_file
                sed -i ":a;N;s/ROS_DESC_CRLF/\n/g;ta" $replace_file
        fi
}

gen_requires()
{
	pkg=$1
	deps_suffix=$2
	require_type=$3
	key_word=$4
	spec=$5

        debug_log "gen ${deps_suffix}"

	package_xml_deps=${ROS_DEPS_BASE}/$pkg-${deps_suffix}
	require_file=${OUTPUT}/.tempRequires

	rm -f ${require_file}

	[ -f ${package_xml_deps} ] && cp ${package_xml_deps} ${require_file}
	spec_fix $pkg $deps_suffix $require_type $key_word $require_file

        if [ ! -f ${require_file} ]
        then
                sed -i "/${key_word}/d" $spec
		return
	fi
	
	rename_requires $require_file

	replace_key_word ${key_word} ${require_file} $spec
}

modify_spec()
{
	pkg=$1
	spec=$2
	pkg_dir_name=$3
	base_version=$4
	release_version=$5

	info_log "Generating spec for $pkg using template $spec"

	# Ensure spec file exists and is readable
	if [ ! -r "$spec" ]; then # Check for readability as well
		error_log "Spec file does not exist or is not readable: $spec"
		exit 1 # Exit if the template spec is missing
	fi

	csrc=`find $pkg_dir_name -name "*.c" | grep -v /test/ | wc -l`
	cppsrc=`find $pkg_dir_name -name "*.cpp" | grep -v /test/ | wc -l`
	no_debug=`grep -P "^${pkg}\$" ${ROOT}/spec_fix/no-debuginfo`

	if [ "$csrc" == "0" -a "$cppsrc" == "0" ] || [ "$no_debug" != "" ]
	then
                sed -i "s#ROS_PACKAGE_NO_DEBUGINFO#%global debug_package %{nil}#g" $spec
	else
                sed -i '/ROS_PACKAGE_NO_DEBUGINFO/d' $spec
	fi

        sed -i "s#ROS_PACKAGE_NAME#$pkg#g" $spec
        sed -i "s#ROS_PACKAGE_VERSION#$base_version#g" $spec
        sed -i "s#ROS_PACKAGE_RELEASE#$release_version#g" $spec

        desc_wc=`cat ${ROS_DEPS_BASE}/$pkg-PackageXml-description | wc -l`
        if [ "$desc_wc" = "1" ]
        then
                desc=`cat ${ROS_DEPS_BASE}/$pkg-PackageXml-description`
                sed -i "s#ROS_PACKAGE_SUMMARY#$desc#g" $spec
                sed -i "s#ROS_PACKAGE_DESCRIPTION#$desc#g" $spec
        else
                desc=`cat ${ROS_DEPS_BASE}/$pkg-PackageXml-description | sed ":a;N;s/\n/ROS_DESC_CRLF/g;ta"`
                sed -i "s#ROS_PACKAGE_SUMMARY#ROS $pkg package#g" $spec
                sed -i "s^ROS_PACKAGE_DESCRIPTION^$desc^g" $spec
                sed -i ":a;N;s/ROS_DESC_CRLF/\n/g;ta" $spec
        fi

        license_wc=`grep license: ${ROS_DEPS_BASE}/$pkg-PackageXml | awk -F"license:" '{print $2}' | wc -l`
        if [ "$license_wc" = "1" ]
        then
                license=`grep license: ${ROS_DEPS_BASE}/$pkg-PackageXml | awk -F"license:" '{print $2}'`
                sed -i "s#ROS_PACKAGE_LICENSE#$license#g" $spec
        else
                license=`grep license: ${ROS_DEPS_BASE}/$pkg-PackageXml | awk -F"license:" '{print $2}' | sed ":a;N;s/\n/ and /g;ta"`
                sed -i "s#ROS_PACKAGE_LICENSE#$license#g" $spec
        fi

        url=`grep url: ${ROS_DEPS_BASE}/$pkg-PackageXml | awk -F"url:" '{print $2}' | sed -n '1p'`
        if [ "$url" = "" ]
        then
                sed -i '/ROS_PACKAGE_URL/d' $spec
        else
                sed -i "s#ROS_PACKAGE_URL#$url#g" $spec
        fi

	gen_requires $pkg Requires Requires ROS_PACKAGE_REQUIRES $spec
	gen_requires $pkg BuildRequires BuildRequires ROS_PACKAGE_BUILDREQUIRES $spec
	gen_requires $pkg test-BuildRequires BuildRequires ROS_TEST_BUILDREQUIRES $spec
	replace_key_word ROS_PROVIDES_FIX ${ROOT}/spec_fix/$pkg.Provides $spec

	if [ "$pkg" == "ament-cmake-core" -o "$pkg" == "ament-package" -o "$pkg" == "ros-workspace" ]
	then
                sed -i '/ROS_ALL_FIX_REQUIRES/d' $spec
	else
                sed -i "s#ROS_ALL_FIX_REQUIRES##g" $spec
	fi

        maintainer=`grep maintainer: ${ROS_DEPS_BASE}/$pkg-PackageXml | awk -F"maintainer:" '{print $2}'`
        changetime=`LC_TIME=en_US.UTF-8 date +"%a %b %d %Y"`
        changelog="$changetime $maintainer - $base_version-$release_version"
        sed -i "s#ROS_PACKAGE_CHANGELOG#$changelog#g" $spec
}

spec_type_fix()
{
	pkg=$1

	spec_type=`grep "$pkg " ${ROOT}/spec_fix/spec-type-fix | cut -d' ' -f2`
	if [ "$spec_type" == "" ]
	then
		return
	fi

	
	if [ "$SRC_TAR_FROM" == "ubuntu" ]
	then
		spec_tplt=${spec_type}-ubuntu.spec
	else
		spec_tplt=${spec_type}.spec
	fi

	cp ${ROOT}/template/${spec_tplt} $pkg.spec
}

package_fix()
{
	pkg=$1
	pkg_repo=$2
    # Pass spec file as argument
    local spec_file=$3

    # Check if spec_file argument is provided
    if [ -z "$spec_file" ]; then
        error_log "package_fix: spec_file argument is missing for package $pkg"
        return 1 # Indicate error
    fi
    # Check if spec_file exists
    if [ ! -f "$spec_file" ]; then
        error_log "package_fix: spec_file does not exist: $spec_file"
        return 1
    fi


	if [ -d "${ROS_PACKAGE_FIX}/$pkg" ]
	then
        info_log "Applying package fixes from ${ROS_PACKAGE_FIX}/$pkg"
		find "${ROS_PACKAGE_FIX}/$pkg" -type f | grep -v "\.fix$" | xargs -i cp {} "$pkg_repo/" # Use quotes
		# Pass spec_file to replace_key_word
		replace_key_word ROS_SOURCE_FIX "${ROS_PACKAGE_FIX}/$pkg/source.fix" "$spec_file"
		replace_key_word ROS_PREP_FIX "${ROS_PACKAGE_FIX}/$pkg/prep.fix" "$spec_file"
	else
        debug_log "No specific package fixes found for $pkg in ${ROS_PACKAGE_FIX}"
        # Apply sed to the passed spec_file
		sed -i '/ROS_SOURCE_FIX/d' "$spec_file"
		sed -i '/ROS_PREP_FIX/d' "$spec_file"
	fi
}

# 定义清理函数
cleanup() {
    info_log "Cleaning up temporary files..."
    rm -f "${OUTPUT}/.repo_pkgs"
    rm -f "${OUTPUT}/.tempRequires"
    # Consider removing specific lock files if needed, or use find
    find "${OUTPUT}" -name '.*.lock' -delete
    # Add any other temp files here
    info_log "Cleanup finished."
}

# 设置 trap
trap 'cleanup' EXIT INT TERM

process_package() {
    local pkg="$1"
    local path="$2"
    local version="$3"
    local repo="$4"
    local temp_pid="$$"

    # 添加锁文件机制
    local lock_file="${OUTPUT}/.${pkg}.lock"
    
    if [ -e "$lock_file" ]; then
        error_log "Another process is handling package $pkg"
        return 1
    fi
    
    touch "$lock_file"
    
    if [ "$pkg" = "" -o "$path" = "" -o "$version" = "" ]; then
        echo "Error: Invalid package details"
        exit 1
    fi

    base_version=`echo $version | awk -F"-" '{print $1}'`
    release_version=`echo $version | awk -F"-" '{print $2}'`

    if [ "$SRC_TAR_FROM" == "ubuntu" ]; then
        # Check if source files exist
        if [ ! -d "${ROS_SRC_BASE}/${repo}" ]; then
            error_log "Source directory not found: ${ROS_SRC_BASE}/${repo}"
            return 1
        fi  # 将 } 改为 fi
        
        # Check for tar.gz files
        pkg_tar=$(find "${ROS_SRC_BASE}/${repo}" -name "ros-${ROS_DISTRO}-${pkg}_*.orig.tar.gz")
        if [ -z "$pkg_tar" ]; then
            error_log "No .orig.tar.gz found for package ${pkg} in ${ROS_SRC_BASE}/${repo}"
            return 1
        fi  # <--- 这里之前是 '}'，已修正为 'fi'
        
        rm -rf ${ROS_SRC_BASE}/${repo}/agiros*
        pkg_dir_name=`cd ${ROS_SRC_BASE}/${repo} && ls ros-${ROS_DISTRO}-${pkg}_*.orig.tar.gz | sed -e "s#.orig.tar.gz##g" | sed -e "s#_#-#g"`
        pkg_tar=`cd ${ROS_SRC_BASE}/${repo} && ls ros-${ROS_DISTRO}-${pkg}_*.orig.tar.gz`
        if [ -f ${ROS_SRC_BASE}/${repo}/${pkg_dir_name}/CMakeLists.txt ]; then
            cp ${ROOT}/template/cmake-ubuntu.spec $pkg.spec
        else
            cp ${ROOT}/template/py-ubuntu.spec $pkg.spec
        fi

        new_pkg_dir_name=$(echo $pkg_dir_name | sed -e "s#ros-${ROS_DISTRO}-#agiros-${AGIROS_DISTRO}-#g")
        
        if [ ! -d "${ROS_SRC_BASE}/${repo}/$pkg_dir_name" ]; then
            error_log "Error: Source directory does not exist: ${ROS_SRC_BASE}/${repo}/$pkg_dir_name"
            exit 1
        fi

        if [ -d "${ROS_SRC_BASE}/${repo}/$new_pkg_dir_name" ]; then
            rm -rf "${ROS_SRC_BASE}/${repo}/$new_pkg_dir_name/*"
        else
            mkdir -p "${ROS_SRC_BASE}/${repo}/$new_pkg_dir_name"
        fi

        if ! cp -r "${ROS_SRC_BASE}/${repo}/$pkg_dir_name/"* "${ROS_SRC_BASE}/${repo}/$new_pkg_dir_name/"; then
            error_log "Failed to copy package files"
            exit 1
        fi

        new_pkg_tar=$(echo $pkg_tar | sed -e "s#ros-${ROS_DISTRO}-#agiros-${AGIROS_DISTRO}-#g")
        tar -czf "${ROS_SRC_BASE}/${repo}/$new_pkg_tar" -C "${ROS_SRC_BASE}/${repo}" "$new_pkg_dir_name"
        cp ${ROS_SRC_BASE}/${repo}/$new_pkg_tar ${ROS_REPO_BASE}/$repo/
        cp -r "${ROS_SRC_BASE}/${repo}/$new_pkg_dir_name/"* "${ROS_REPO_BASE}/$repo/"

        pkg_dir_name=${ROS_SRC_BASE}/${repo}/$pkg_dir_name
    else
        pkg_dir_name=$pkg-$base_version
        mkdir -p $pkg_dir_name
        cp -r ${ROS_SRC_BASE}/$path/* $pkg-$base_version/
        tar -czf $pkg-$base_version.tar.gz $pkg-$base_version

        if [ -f $pkg-$base_version/setup.py ]; then
            cp ${ROOT}/template/py.spec $pkg.spec
        else
            cp ${ROOT}/template/cmake.spec $pkg.spec
        fi
    fi
    
    spec_type_fix $pkg
    # 需要将 $pkg.spec 作为第三个参数传递给 modify_spec 和 package_fix
    local spec_file="$pkg.spec" 
    modify_spec $pkg "$spec_file" "$pkg_dir_name" "$base_version" "$release_version"
    # 将 spec_file 传递给 package_fix
    package_fix $pkg "${ROS_REPO_BASE}/${repo}" "$spec_file" 
}

process_repo() {
    info_log "Starting to process repo: $1"
    local repo=$1
    local specific_pkg=$2

    info_log "Creating repo directory: ${ROS_REPO_BASE}/${repo}/"
    mkdir -p "${ROS_REPO_BASE}/${repo}/"
    cd "${ROS_REPO_BASE}/${repo}/"

    info_log "Creating package list for repo $repo"
    grep -P "[[:blank:]]$repo[[:blank:]]" ${ROS_PKG_SRC} >${OUTPUT}/.repo_pkgs
    grep -P "[[:blank:]]$repo/" ${ROS_PKG_SRC} >>${OUTPUT}/.repo_pkgs

    if [ -z "$specific_pkg" ]; then
        echo "<multibuild>" >_multibuild
    fi

    local pkg_num=0
    local total_pkgs=$(wc -l < ${OUTPUT}/.repo_pkgs)
    local current_pkg=0

    echo "Total packages to process: $total_pkgs"

    while read pkg path version; do
        echo "Processing package: $pkg"
        if [ -n "$specific_pkg" ] && [ "$pkg" != "$specific_pkg" ]; then
            echo "Skipping package $pkg (not the specific package)"
            continue
        fi

        process_package "$pkg" "$path" "$version" "$repo"

        if [ -z "$specific_pkg" ]; then
            echo -e "\t<flavor>$pkg</flavor>" >>_multibuild
        fi

        pkg_num=$((pkg_num + 1))
        current_pkg=$((current_pkg + 1))
        echo "Processed package $pkg ($current_pkg/$total_pkgs)"
    done < ${OUTPUT}/.repo_pkgs

    if [ -z "$specific_pkg" ]; then
        echo "</multibuild>" >>_multibuild
        [ $pkg_num -lt 2 ] && rm _multibuild
    fi
}

main()
{
    echo "Starting main function"
    prepare
    ##for debug
    # specific_pkg=ament-cmake-test

    if [ -n "$specific_pkg" ]; then
        echo "Processing specific package: $specific_pkg"
        repo=$(grep -P "^${specific_pkg}[[:blank:]]" ${ROS_PKG_SRC} | awk '{print $2}' | cut -d'/' -f1)
        if [ -z "$repo" ]; then
            echo "Error: Package $specific_pkg not found in ${ROS_PKG_SRC}"
            exit 1
        fi
        process_repo "$repo" "$specific_pkg"
    else
        echo "Processing all packages"
        for repo in $(cat ${ROS_PKG_LIST} | awk '{print $2}' | sort | uniq); do
            process_repo "$repo" ""
        done
    fi

    echo "Gen ros-pkg-src.list done, you can find it in ${ROS_PKG_SRC}"
}

# 添加调试模式
if [ "$DEBUG" = "1" ]; then
    set -x
fi

main
